package com.base.filter;

import cn.hutool.core.util.ObjUtil;
import cn.hutool.jwt.JWTUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.base.annotation.HasPermission;
import com.base.common.RedisCache;
import com.base.constant.Constants;
import com.base.domain.SysUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.HandlerMapping;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

/**
 * @author gxd
 * @since 2025/6/7
 */
@Slf4j
public class SystemFilter implements Filter {

    private RedisCache redisCache;

    public SystemFilter(RedisCache redisCache) {
        this.redisCache = redisCache;
    }

    private List<HandlerMapping> handlerMappings;

    // 需要放行的路径
    private static final List<String> WHITE_LIST = Arrays.asList(
            "/login",
            "/doc.html",
            "/swagger-ui/**",
            "/swagger-ui.html",
            "/swagger-resources/**",
            "/webjars/**",
            "/*/api-docs",
            "/*.html",
            "/**/*.html",
            "/**/*.css",
            "/**/*.js",
            "/profile/**"
    );
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 获取Spring应用上下文
        WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(
                filterConfig.getServletContext()
        );

        // 获取所有HandlerMapping实例
        handlerMappings = new ArrayList<>(ctx.getBeansOfType(HandlerMapping.class).values());
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        String requestURI = httpRequest.getRequestURI();
        if (isWhiteList(requestURI)) {
            chain.doFilter(request, response);
            return;
        }

        // 校验token是否有效
        String token = httpRequest.getHeader("Authorization");
        if (ObjUtil.isNull(token) || !JWTUtil.verify(token, Constants.SECRET_KEY.getBytes())) {
            httpResponse.sendRedirect("/login");
            return;
        }

        // 校验当前登录人是否有权限访问当前接口路径
        String tokenKey = Constants.LOGIN_TOKEN_KEY + token;
        JSONObject jsonObject = redisCache.getCacheObject(tokenKey);
        SysUser user = JSON.parseObject(jsonObject.toJSONString(), SysUser.class);
        Set<String> permissions = user.getPermissions();

        HandlerExecutionChain handlerChain = null;
        // 1. 遍历HandlerMapping解析请求对应的处理器
        for (HandlerMapping mapping : handlerMappings) {
            try {
                handlerChain = mapping.getHandler(httpRequest);
                if (handlerChain != null) break;
            } catch (Exception e) {
                // 处理异常
            }
        }

        // 2. 检查是否找到处理器方法
        if (handlerChain != null && handlerChain.getHandler() instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handlerChain.getHandler();

            // 3. 获取方法上的HasPermission注解
            HasPermission annotation = handlerMethod.getMethod().getAnnotation(HasPermission.class);

            if (annotation != null) {
                String permissionCode = annotation.value();

                // 4. 执行权限验证逻辑
                if (!checkPermission(permissions, permissionCode)) {
                    throw new RuntimeException("当前用户不具备访问权限");
                }
            }
        }

        chain.doFilter(request, response);
    }

    private boolean isWhiteList(String requestURI) {
        AntPathMatcher matcher = new AntPathMatcher();
        return WHITE_LIST.stream().anyMatch(whitePath ->
                matcher.match(whitePath, requestURI)
        );
    }

    private boolean checkPermission(Set<String> permissions, String permissionCode) {
        return permissions.contains(permissionCode) || permissions.contains(Constants.All_PERMISSION);
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}
